/*
    This file is part of Epoch <http://code.google.com/p/epoch/>.

    Copyright (C) 2011 Adam Meily <meily.adam@gmail.com>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License along
    with this program; if not, write to the Free Software Foundation, Inc.,
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/


#include "ChronosConfig.h"
#include "../Models/RemoteDevice.h"
#include <QtCore/QSettings>
#include <QtNetwork/QHostAddress>
#include <Logger.h>

ChronosConfig::~ChronosConfig()
{
    if(m_dbConfig)
        delete m_dbConfig;
    
    if(m_shellConfig)
        delete m_shellConfig;
}

const DatabaseConfig* ChronosConfig::dbConfig() const
{
    return m_dbConfig;
}

const ShellConfig* ChronosConfig::shellConfig() const
{
    return m_shellConfig;
}

const QList< quint32 > ChronosConfig::localAddresses() const
{
    return m_localAddresses;
}

const QString& ChronosConfig::logFilePath() const
{
    return m_logFilePath;
}

bool ChronosConfig::isLocalAddress(quint32 addr) const
{
    bool local = false;
    QListIterator<quint32> i(m_localAddresses);
    while(i.hasNext() && !local)
        local = ((i.next() & addr) == addr);
    return local;
}

QFile ChronosConfig::deltaFile(const Revision& revision) const
{
    return baseFile(revision, "delta");
}

QFile ChronosConfig::fullFile(const Revision& revision) const
{
    return baseFile(revision, "full");
}

QFile ChronosConfig::signatureFile(const Revision& revision) const
{
    return baseFile(revision, "sig");
}

QDir ChronosConfig::baseFile(const Revision& revision, const QString& ext) const
{
    return QFile(
        m_storageRoot.absoluteFilePath(
            QString("%0/%1/%2-%3.%4")
                .arg(revision.share().device().uuid().toHex())
                .arg(revision.share().uuid().toHex())
                .arg(revision.uuid().toHex())
                .arg(QString::number(revision.reivision(), 10))
                .arg(ext)
        )
    );
}

ChronosConfig* ChronosConfig::parse(const QString& configPath, QString* error)
{
    QSettings config(configPath, QSettings::IniFormat);
    
    /* Root Directory */
    QString root = config.value("storage-root", "").toString();
    QDir rootDir(QDir(root).absolutePath());
    
    /* Key */
    QString keystr = config.value("key", "").toString();
    QByteArray key = QByteArray::fromHex(keystr.toUtf8());
    if(key.length() != 32)
    {
        *error = "Invalid key";
        return 0;
    }
    
    /* Database */
    DatabaseConfig *db = DatabaseConfig::parse(config, error);
    if(!db)
        return 0;
    
    /* Log File */
    QString logpath = config.value("log", "/var/log/chronos.log").toString();
    QIODevice *device;
    if(logpath == "stdout")
    {
        QFile *log = new QFile();
        log->open(stdout, QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate);
        device = log;
    }
    else
    {
        QFile *log = new QFile(logpath);
        if(!log->open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate))
        {
            *error = "Could not open log file `" + log->fileName() + "`";
            return 0;
        }
        device = log;
    }
    
    bool ok;
    quint16 port = config.value("port", 6521);
    if(!ok)
        port = 6521;
    
    QString logLevelStr = config.value("log-level", "").toString();
    Logger::Level level = Logger::Debug;
    if(logLevelStr == "info")
        level = Logger::Info;
    else if(logLevelStr == "error")
        level = Logger::Error;
    
    /* Local Addresses */
    QList<quint32> localAddresses;
    QString locals = config.value("local-addrs", "").toString();
    if(!locals.isEmpty())
    {
        QStringList list = locals.split(",", QString::SkipEmptyParts);
        int len = list.length();
        for(int i = 0; i < len; i++)
        {
            QHostAddress addr(list[i]);
            localAddresses.append(addr.toIPv4Address());
        }
    }
    
    ShellConfig *shell = ShellConfig::parse(config, error);
    if(!shell)
        return 0;
    
    ChronosConfig *cc = new ChronosConfig();
    cc->m_dbConfig = db;
    cc->m_key = key;
    cc->m_localAddresses = localAddresses;
    cc->m_logFilePath = logpath;
    cc->m_shellConfig = shell;
    cc->m_storageRoot = rootDir;
    cc->m_port = port;
    
    Logger::init(device, level);
    return cc;
}


